Skip to content

feat: REPL prompt history, paste newline folding, and /new session swap - #84

Merged
william0wang merged 14 commits into
mainfrom
feat/repl-history-paste-new
Aug 31, 2026
Merged

feat: REPL prompt history, paste newline folding, and /new session swap#84
william0wang merged 14 commits into
mainfrom
feat/repl-history-paste-new

Conversation

@william0wang

Copy link
Copy Markdown
Owner

Summary

Daily-driver batch for the bare zcode-acp REPL — three features plus hardening from a strong-model review pass:

  • Per-project prompt history — every submit (slash commands included, verbatim) is recorded to ~/.zcode/acp/repl-history/<sha1(cwd)>.jsonl (newest 500 kept, consecutive duplicates collapsed, malformed lines tolerated). / with the completion menu closed recalls entries across restarts; the first stashes the live draft and past the newest restores it. The in-memory list is bounded to the same cap as the file.
  • Paste newline folding — pasted text folds to a single line (newlines/tabs → single spaces) so a multi-paragraph paste lands as one editable prompt instead of firing line-by-line as separate submits. Bracketed pastes ride ink 7's dedicated usePaste channel (which also arms/disarms ?2004 with the hook lifecycle — no manual terminal-mode management); terminals without bracketed-paste fall back to a heuristic that folds only chunks carrying a real \n, so coalesced keystroke bursts ("x\r" from fast typing) keep their submit semantics. The size cap counts code points and never splits a surrogate pair.
  • /new session swap — REPL-local command that swaps the live session for a fresh backend-created one, strictly client-side so the update pump never loses the session id. Reseeds the model/mode/thought selects from the new session's response, clears the prompt draft, and appends a divider note (the old conversation stays in /sessions and in native scrollback — entries are append-only under ink <Static>). Refuses while a turn runs or startup is in flight. Registered as a one-shot command: enter-on-pick in the completion menu executes immediately.

Review hardening (all audit findings fixed)

  • /new re-checks turnActive after the session/new roundtrip: a turn racing into the old session mid-swap used to orphan it (pump disposed, completion filtered by session id) and wedge the REPL with turnActive stuck forever.
  • Paste heuristic narrowed to require a real \n (fixes silent submit loss on fast-typed "x\r" chunks).
  • Queue drain re-entering onSubmit no longer double-records queued prompts into history.
  • The crash circuit breaker now unmounts ink so its stdin cleanup effects (raw mode, bracketed paste) still run — previously that path leaked raw mode.

Test plan

  • pnpm lint / pnpm typecheck / pnpm test — 811 tests green (new: history file IO + dedupe + cap, paste folding boundaries incl. surrogate pair at the cap, /new command registration and one-shot set)
  • Six-leg tmux pty smoke (capture-pane, zero model calls): plain submit, wrapped paste, legacy heuristic paste, lone-Enter submit, /new divider, restart recall — all pass
  • Menu probe on backend 0.16.5: no duplicate new row (backend does not advertise one; the commandMenu name-merge covers the case if a future backend does)

Docs: README REPL section, CHANGELOG, AGENTS.md source tree. Design records: ADR-0008 (prompt history), ADR-0009 (paste folding), ADR-0010 (/new and session swap) in the project's local .zcode/docs/adr/.

@william0wang
william0wang merged commit 4a408f0 into main Aug 31, 2026
1 check passed
@william0wang
william0wang deleted the feat/repl-history-paste-new branch August 31, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant